#include "Piece.h"

class PieceManager{
public:
  	PieceManager();
	
	void createPiece(int type, int team, int xpos, int ypos);
	int getPiece(int xpos, int ypos);
	void placePiece(int xpos, int ypos, int id);
	int movePiece(int xpos, int ypos, int id);

	Piece* getPiece(int id);
	
	vector<vector<int> > getPotMoves(int id);
	vector<vector<int> > getMap();
	vector<vector<int> > getOffPieces();
	vector<vector<int> > getOnPieces();

	int status();
	void updateStatus();
	void autoSetup();
	void display();
private:
	void attack(int attacker, int defender, int contested_x, int contested_y);
	void deletePiece(int id);

	int curTeam, curPiece, gameStatus;

	vector<vector<int> > map;
	vector<vector<int> > off_pieces;
	vector<vector<int> > on_pieces;
	
	vector<Piece> index;
	vector<vector<int> > potentialMoves;
};
PieceManager::PieceManager(){
	map.resize(MAXCOLS);
	for(int pos = 0; pos < 10; pos++)
		map[pos].resize(MAXROWS,-1);
	for(int num = 0; num < numLakeCells; num++)
		map[lake_cells[num][0]][lake_cells[num][1]] = -2;
	off_pieces.resize(2);
	on_pieces.resize(2);
	for(int tm = 0; tm < 2; tm++){
		int count = 0;
		for(int tp = 0; tp < 12; tp++){
			for(int num = 0; num < piece_totals[tp]; num++){
				int x,y;
				if(tp <= 9)
					x = tp;
				else
					x = 4+(tp%10);
				if(tm == BLUE)
					y = (11 + (tp/10));
				else 
					y = (-2 - (tp/10));
				createPiece(tp,tm,x,y);
				count++;
			}
		}
	}
	updateStatus();
}
void PieceManager::createPiece(int type, int team, int xpos, int ypos){
	Piece temp(type, team, 0, 0);
	temp.setID(index.size());
	temp.moveTo(xpos,ypos);
	off_pieces[team].push_back(index.size());
	index.push_back(temp);
}
int PieceManager::getPiece(int xpos, int ypos){
	int value = -3;
	if(xpos >= 0 && xpos < 10 && ypos >= 0 && ypos < 10){
		value = map[xpos][ypos];
	}
	else{
		Piece *temp;
		for(int team = 0; team < 2; team++){
			for(int pos = 0; pos < off_pieces[team].size(); pos++){
				temp = &index[off_pieces[team][pos]];
				if(xpos == temp->x() && ypos == temp->y())
					value = temp->getID();
			}
		}
	}
	return value;
}
void PieceManager::placePiece(int xpos, int ypos, int id){
	if(!(xpos < 0 || xpos >= MAXROWS || ypos < 0 || ypos >= MAXCOLS)){
		if(map[xpos][ypos] != -2){
			bool done = false;
			for(int pos = 0; pos < off_pieces[index[id].getTeam()].size() && !done; pos++){
				if(off_pieces[index[id].getTeam()][pos] == id){
					off_pieces[index[id].getTeam()].erase(off_pieces[index[id].getTeam()].begin()+pos);
					on_pieces[index[id].getTeam()].push_back(id);
					done = true;
				}
			}
			index[id].moveTo(xpos, ypos);	
			map[xpos][ypos] = id;
		}
	}
	updateStatus();
}
int PieceManager::movePiece(int xpos, int ypos, int id){
	int val;
	vector<vector<int> > potentialMoves = getPotMoves(id);
	
	if(xpos < 0 || xpos >= MAXROWS || ypos < 0 || ypos >= MAXCOLS)
		val = 0;
	else if(id >= index.size())
		val = 0;
	else if(potentialMoves[xpos][ypos] == 0)
		val = 0;
	else if(potentialMoves[xpos][ypos] == 1){
		map[index[id].x()][index[id].y()] = -1;
		placePiece(xpos, ypos, id);
		val = 1;
	}
	else if(potentialMoves[xpos][ypos] == 2){
		map[index[id].x()][index[id].y()] = -1;
		attack(id,map[xpos][ypos],xpos,ypos);
		val = 2;
	}
	updateStatus();
	return val;
}
Piece* PieceManager::getPiece(int id){
	return &index[id];
}			
vector<vector<int> > PieceManager::getPotMoves(int id){
	int pos[2], type, team;
	bool done = false;

	vector<vector<int> > pot_moves;
	pot_moves.resize(10);
	for(int pos = 0; pos < 10; pos++)
		pot_moves[pos].resize(10,0);

	pos[0] = index[id].x();
	pos[1] = index[id].y();
	type = index[id].getType();
	team = index[id].getTeam();

	if(type == SCOUT){
		for(int x = pos[0]+1; x < 10 && !done; x++){
			int temp = map[x][pos[1]];
			if(temp == -2)
				done = true;
			else if(temp == -1)
				pot_moves[x][pos[1]] = 1;
			else if(index[temp].getTeam() == team)
				 done = true;
			else{
				pot_moves[x][pos[1]] = 2;
				done = true;
			}
		}
		done = false;
		for(int x = pos[0]-1; x >= 0 && !done; x--){
			int temp = map[x][pos[1]];
			if(temp == -2)
				done = true;
			else if(temp == -1)
				pot_moves[x][pos[1]] = 1;
			else if(index[temp].getTeam() == team)
				 done = true;
			else{
				pot_moves[x][pos[1]] = 2;
				done = true;
			}
		}
		done = false;
		for(int y = pos[1]-1; y >= 0 && !done; y--){
			int temp = map[pos[0]][y];
			if(temp == -2)
				done = true;
			else if(temp == -1)
				pot_moves[pos[0]][y] = 1;
			else if(index[temp].getTeam() == team)
				 done = true;
			else{
				pot_moves[pos[0]][y] = 2;
				done = true;
			}
		}
		done = false;
		for(int y = pos[1]+1; y < 10 && !done; y++){
			int temp = map[pos[0]][y];
			if(temp == -2)
				done = true;
			else if(temp == -1)
				pot_moves[pos[0]][y] = 1;
			else if(index[temp].getTeam() == team)
				 done = true;
			else{
				pot_moves[pos[0]][y] = 2;
				done = true;
			}
		}
	}
	else if(type != FLAG && type != BOMB){
		if((pos[0]-1) >= 0){
			int temp = map[pos[0]-1][pos[1]];
			if(temp == -1)
				pot_moves[pos[0]-1][pos[1]] = 1;
			else if(index[temp].getTeam() != team)
				pot_moves[pos[0]-1][pos[1]] = 2;
		}
		if((pos[0]+1) < 10){
			int temp = map[pos[0]+1][pos[1]];
			if(temp == -1)
				pot_moves[pos[0]+1][pos[1]] = 1;
			else if(index[temp].getTeam() != team)
				pot_moves[pos[0]+1][pos[1]] = 2;
		}
		if((pos[1]+1) < 10){
			int temp = map[pos[0]][pos[1]+1];
			if(temp == -1)
				pot_moves[pos[0]][pos[1]+1] = 1;
			else if(index[temp].getTeam() != team)
				pot_moves[pos[0]][pos[1]+1] = 2;
		}
		if((pos[1]-1) >= 0){
			int temp = map[pos[0]][pos[1]-1];
			if(temp == -1)
				pot_moves[pos[0]][pos[1]-1] = 1;
			else if(index[temp].getTeam() != team)
				pot_moves[pos[0]][pos[1]-1] = 2;
		}
	}
	return pot_moves;
}
vector<vector<int> > PieceManager::getMap(){
	return map;
}
vector<vector<int> > PieceManager::getOffPieces(){
	return off_pieces;
}
vector<vector<int> > PieceManager::getOnPieces(){
	return on_pieces;
}
void PieceManager::attack(int attacker, int defender, int contested_x, int contested_y){
	if(index[attacker].attack(index[defender].getType()) == 3){
		if(index[attacker].getTeam() == 0)
			gameStatus = P1WON;
		else
			gameStatus = P1WON;
	}
	else if(index[attacker].attack(index[defender].getType()) == 2){
		deletePiece(attacker);
		deletePiece(defender);
	}
	else if(index[attacker].attack(index[defender].getType()) == 1){
		deletePiece(defender);
		placePiece(contested_x, contested_y, attacker);
	}
	else
		deletePiece(attacker);
	updateStatus();
}
void PieceManager::deletePiece(int id){
	if(index[id].x() >= 0 && index[id].y() >= 0 && index[id].x() < 10 && index[id].y() < 10){
		map[index[id].x()][index[id].y()] = -1; 
		index[id].moveTo(-1,-1);
	}
	bool done = false;
	for(int pos = 0; pos < on_pieces[index[id].getTeam()].size() && !done; pos++){
		if(on_pieces[index[id].getTeam()][pos] == id){
			on_pieces[index[id].getTeam()].erase(on_pieces[index[id].getTeam()].begin()+pos);
			done = true;
		}
	}
	done = false;
	for(int pos = 0; pos < off_pieces[index[id].getTeam()].size() && !done; pos++){
		if(off_pieces[index[id].getTeam()][pos] == id){
			off_pieces[index[id].getTeam()].erase(off_pieces[index[id].getTeam()].begin()+pos);
			done = true;
		}
	}
}
void PieceManager::updateStatus(){
	if(off_pieces[0].size() > 0 || off_pieces[1].size() > 0){
		gameStatus = SETUP;
	}
	else if(!(gameStatus == P1WON || gameStatus == P2WON || gameStatus == STALEMATE)){
		bool p1canmove = false, p2canmove = false;
		for(int pos = 0; pos < on_pieces[0].size(); pos++){
			if(on_pieces[0][pos] != FLAG && on_pieces[0][pos] != BOMB)
				p1canmove = true;
		}
		for(int pos = 0; pos < on_pieces[1].size(); pos++){
			if(on_pieces[1][pos] != FLAG && on_pieces[1][pos] != BOMB)
				p2canmove = true;
		}
		if(p1canmove && p2canmove)
			gameStatus = UNDECIDED;
		else if(p1canmove && !p2canmove)
			gameStatus = P1WON;
		else if(!p1canmove && p2canmove)
			gameStatus = P2WON;
		else if(!p1canmove && !p2canmove)
			gameStatus = STALEMATE;
	}
}
void PieceManager::autoSetup(){
	for(int x = 0; x < 10; x++){
		for(int y = 0; y < 4; y++)
			placePiece(x,y,off_pieces[RED][0]);
	}
	for(int x = 0; x < 10; x++){
		for(int y = 6; y < 10; y++)
			placePiece(x,y,off_pieces[BLUE][0]);
	}
}		  
int PieceManager::status(){
	return gameStatus;
}
void PieceManager::display(){
	for(int pos2 = 9; pos2 >= 0; pos2--){
		for(int pos = 0; pos < 10; pos++){
			if(map[pos][pos2] >= 0)
				cout << " " << setw(2) << index[map[pos][pos2]].getType() << "|";
			else if(map[pos][pos2] == -1)
				cout << "   |";
			else
				cout << "www|";
		}
		cout << endl;
	}
	cout << endl;
	for(int pos2 = 9; pos2 >= 0; pos2--){
		for(int pos = 0; pos < 10; pos++){
			if(map[pos][pos2] >= 0)
				cout << " " << setw(2) << map[pos][pos2] << "|";
			else if(map[pos][pos2] == -1)
				cout << "   |";
			else
				cout << "www|";
		}
		cout << endl;
	}
	cout << endl;
}		
